﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Hibiku.Twitter
{
    public class Param
    {
        public static string ToPercentEncoded(char ch)
        {
            return string.Format("%{0:X}", (int)ch);
        }

        private static readonly char[] s_reserved = new char[] {'%', ' ', '!', '*', '\'', '(', ')', ';', ':', '@', '&', '=', '+', '$', ',', '/', '?', '#', '[', ']', '|', '"' };
        private static readonly Dictionary<char, string> s_replacements = s_reserved.ToDictionary(x => x, x => ToPercentEncoded(x));
        
        public static string PercentEncode(string text)
        {
            var buffer = new StringBuilder(text.Length * 2);

            foreach (var b in Encoding.UTF8.GetBytes(text))
            {
                var ch = Convert.ToChar(b);

                if (s_replacements.ContainsKey(ch))
                {
                    buffer.Append(s_replacements[ch]);
                }
                else if (b >= 128)
                {
                    buffer.Append(ToPercentEncoded(ch));
                }
                else
                {
                    buffer.Append(ch);
                }
            }

            return buffer.ToString();
        }

        public enum EParamType
        {
            OAuth,
            Query,
            Body
        }

        public String Key
        {
            get;
            private set;
        }

        public string Value
        {
            get;
            private set;
        }

        public EParamType ParamType
        {
            get;
            private set;
        }

        public Param(string key, string value) : this(key, value, EParamType.OAuth)
        {
        }

        public Param(string key, string value, EParamType paramType)
        {
            Key = key;
            Value = value;
            ParamType = paramType;
        }

        public override string ToString()
        {
            return string.Format("{0}={1}", Key, PercentEncode(Value));
        }
    }

    public static class ParamExtensions
    {
        public static string ToOAuthValue(this IEnumerable<Param> params_)
        {
            var argsString = string.Join(", ", params_.Where(x => x.ParamType == Param.EParamType.OAuth).Select(x => string.Format(@"{0} = ""{1}""", x.Key, Param.PercentEncode(x.Value))));

            return "OAuth " + argsString;
        }

        public static string ToOAuthBaseString(this IEnumerable<Param> params_, string method, string urlWithoutPortAndQuery)
        {
            var queryRaw = string.Join("&", params_.Where(x => x.ParamType == Param.EParamType.Query || x.ParamType == Param.EParamType.OAuth).OrderBy(x => x.Key));

            return string.Format("{0}&{1}&{2}", method, Param.PercentEncode(urlWithoutPortAndQuery), Param.PercentEncode(queryRaw));
        }

        public static string ToQueryString(this IEnumerable<Param> params_)
        {
            return string.Join("&", params_.Where(x => x.ParamType == Param.EParamType.Query).OrderBy(x => x.Key));
        }
    }
}
